home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / deleteuser / deleteuser.c < prev    next >
C/C++ Source or Header  |  1991-12-16  |  11KB  |  410 lines

  1. /* 
  2.  * deleteuser.c --
  3.  *
  4.  *    Delete a users account, remove all their files, remove
  5.  *      them from /etc/passwd and take them off the sprite-users
  6.  *      mailing list.
  7.  *      
  8.  * Copyright 1990 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/admin/deleteuser/RCS/deleteuser.c,v 1.7 91/12/16 12:10:27 kupfer Exp $";
  20. #endif /* not lint */
  21.  
  22.  
  23. #include "common.h"
  24. #include <sprite.h>
  25. #include <bstring.h>
  26. #include <errno.h>
  27. #include <fcntl.h>
  28. #include <libc.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <sys/file.h>
  33. #include <sys/ioctl.h>
  34. #include <sys/param.h>
  35. #include <sys/stat.h>
  36. #include <sys/types.h>
  37. #include <sys/wait.h>
  38. #include <unistd.h>
  39.  
  40. /* Forward references: */
  41. static void removeFromMailingLists _ARGS_((CONST char *username));
  42. static void deletePasswdEntry _ARGS_((CONST char *username));
  43. static void removeHomeDirectory _ARGS_((CONST char *homedir));
  44.  
  45.  
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * main --
  50.  *
  51.  *    Process arguments, set uid and signals; then remove users.
  52.  *
  53.  * Results:
  54.  *    None.
  55.  *
  56.  * Side effects:
  57.  *    None.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61.  
  62. void
  63. main(argc, argv)
  64.     int argc;
  65.     CONST char **argv;
  66. {
  67.     int i;
  68.     CONST char *username;
  69.     struct passwd *pwd;
  70.     char homeDir[MAXPATHLEN];
  71.  
  72.     if(argc < 2 || *argv[1] == '-') {
  73.     (void) fprintf(stderr, "Usage: %s username [username ...]\n", argv[0]);
  74.     (void) fprintf(stderr, "Remove sprite accounts.\n");
  75.     exit(EXIT_FAILURE);
  76.     }
  77. #ifndef TEST
  78.     /* 
  79.      * Verify that we're running as root, so as to avoid unpleasant 
  80.      * surprises later.  Because the program is installed setuid, make 
  81.      * sure that the invoking user is in the wheel group.
  82.      */
  83.     SecurityCheck();
  84. #endif
  85.     printf("This program will delete the accounts and erase\n");
  86.     printf("all the files in the home directories.\n");
  87.     if (!yes("Are you sure you want to do this?")) {
  88.     printf("\nquitting\n");
  89.     exit(EXIT_FAILURE);
  90.     }
  91.     (void) signal(SIGHUP, SIG_IGN);
  92.     (void) signal(SIGINT, SIG_IGN);
  93.     (void) signal(SIGQUIT, SIG_IGN);
  94.     (void) signal(SIGTSTP, SIG_IGN);
  95.  
  96.     /* 
  97.      * For each username, try to get the home directory from the 
  98.      * password file.  If that fails, ask the user if we should 
  99.      * continue (e.g., maybe the user was already removed from the 
  100.      * password file, but not the aliases file).  If the user says to
  101.      * continue, we guess at the home directory.  (XXX We should ask
  102.      * the user.)
  103.      */
  104.     setpwfile(MASTER_PASSWD_FILE);
  105.     if (setpwent() == 0) {
  106.     fprintf(stderr, "Can't change password file to %s\n",
  107.         MASTER_PASSWD_FILE);
  108.     exit(EXIT_FAILURE);
  109.     }
  110.     for (i = 1; i < argc; ++i) {
  111.     username = argv[i];
  112.     if ((pwd = getpwnam(username)) == NULL) {
  113.         fprintf(stderr, "%s: no such user\n", username);
  114.         if (yes("Skip this user?")) {
  115.         continue;
  116.         }
  117.     }
  118.     removeFromMailingLists(username);
  119.  
  120.     /* 
  121.      * If we don't know what the user's home directory is, guess 
  122.      * that it's the default.
  123.      */
  124.     if (pwd != NULL) {
  125.         removeHomeDirectory(pwd->pw_dir);
  126.     } else {
  127.         strcpy(homeDir, USER_DIR);
  128.         strcat(homeDir, "/");
  129.         strcat(homeDir, username);
  130.         removeHomeDirectory(homeDir);
  131.     }
  132.     deletePasswdEntry(username);
  133.     }
  134.     exit(EXIT_SUCCESS);
  135. }
  136.  
  137.  
  138. /*
  139.  *----------------------------------------------------------------------
  140.  *
  141.  *  deletePasswdEntry --
  142.  *
  143.  *      Removes a user's entry from the password file.
  144.  *
  145.  * Results:
  146.  *    none.
  147.  *
  148.  * Side effects:
  149.  *
  150.  *      Exits if there is a system error.
  151.  *
  152.  *----------------------------------------------------------------------
  153.  */
  154. static void
  155. deletePasswdEntry(username)
  156.     CONST char *username;
  157. {
  158.     FILE *tmpfile;
  159.     int fd;
  160.     struct passwd *pwd;
  161.     int found = 0;
  162.     char from[MAXPATHLEN], to[MAXPATHLEN], *tend, *fend;
  163.     char buf1[16], buf2[16];
  164.  
  165.  
  166.     (void) printf("Removing %s from %s.\n", username, MASTER_PASSWD_FILE);
  167.     if ((fd = open(PTMP_FILE, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) {
  168.     (void) fprintf(stderr, "Cannot open %s: %s\n",
  169.         PTMP_FILE, strerror(errno));
  170.     exit(EXIT_FAILURE);
  171.     }
  172.     if ((tmpfile = fdopen(fd, "w")) == NULL) {
  173.     (void) fprintf(stderr, "Absurd fdopen failure - seek help\n");
  174.     (void) unlink(PTMP_FILE);
  175.     exit(EXIT_FAILURE);
  176.     }
  177.     while ((pwd = getpwent()) != NULL) {
  178.     if (strcmp(pwd->pw_name, username) == 0) {
  179.         ++found;
  180.     } else {
  181.         if (pwd->pw_change==0) {
  182.         *buf1 = '\0';
  183.         } else {
  184.         sprintf(buf1,"%l",pwd->pw_change);
  185.         }
  186.         if (pwd->pw_expire==0) {
  187.         *buf2 = '\0';
  188.         } else {
  189.         sprintf(buf2,"%l",pwd->pw_expire);
  190.         }
  191.         fprintf(tmpfile, "%s:%s:%d:%d:%s:%s:%s:%s:%s:%s\n",
  192.             pwd->pw_name,
  193.             pwd->pw_passwd,
  194.             pwd->pw_uid,
  195.             pwd->pw_gid,
  196.             pwd->pw_class,
  197.             buf1,
  198.             buf2,
  199.             pwd->pw_gecos,
  200.             pwd->pw_dir,
  201.             pwd->pw_shell);
  202.     }
  203.     }
  204.     (void) endpwent();
  205.     (void) fclose(tmpfile);
  206.  
  207.     if (found == 0) {
  208.     (void) fprintf(stderr, "There is no entry for %s in %s.\n",
  209.                username, MASTER_PASSWD_FILE);
  210.     (void) unlink(PTMP_FILE);
  211.     return;
  212.     }
  213.     if (makedb(PTMP_FILE)) {
  214.     (void) fprintf(stderr, "makedb failed!\n");
  215.     exit(EXIT_FAILURE);
  216.     }
  217.  
  218.     /*
  219.      * possible race; have to rename four files, and someone could slip
  220.      * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
  221.      * so that getpwent(3) can't slip in; the lock should never fail and
  222.      * it's unclear what to do if it does.  Rename ``ptmp'' last so that
  223.      * passwd/vipw/chpass can't slip in.
  224.      */
  225.     fend = strcpy(from, PTMP_FILE) + strlen(PTMP_FILE);
  226.     tend = strcpy(to, PASSWD_FILE) + strlen(PASSWD_FILE);
  227.     bcopy(".dir", fend, 5);
  228.     bcopy(".dir", tend, 5);
  229.     if ((fd = open(from, O_RDONLY, 0)) >= 0) {
  230.     (void)flock(fd, LOCK_EX);
  231.     /* here we go... */
  232.     if (rename(from, to)) {
  233.         (void) fprintf(stderr, "Cannot rename %s: %s\n",
  234.         from, strerror(errno));
  235.     }
  236.     bcopy(".pag", fend, 5);
  237.     bcopy(".pag", tend, 5);
  238.     if (rename(from, to)) {
  239.         (void) fprintf(stderr, "Cannot rename %s: %s\n",
  240.         from, strerror(errno));
  241.     }
  242.     }
  243.     bcopy(".orig", fend, 6);
  244.     if (rename(PASSWD_FILE, PASSWD_BAK)) {
  245.     (void) fprintf(stderr, "Cannot rename %s: %s\n",
  246.         from, strerror(errno));
  247.     }
  248.     if (rename(MASTER_PASSWD_FILE, MASTER_BAK)) {
  249.     (void) fprintf(stderr, "Cannot rename %s: %s\n",
  250.         MASTER_PASSWD_FILE, strerror(errno));
  251.     }
  252.     if (rename(from, PASSWD_FILE)) {
  253.     (void) fprintf(stderr, "Cannot rename %s: %s\n",
  254.         PASSWD_FILE, strerror(errno));
  255.     }
  256.     if (rename(PTMP_FILE, MASTER_PASSWD_FILE)) {
  257.     (void) fprintf(stderr, "Cannot rename %s: %s\n",
  258.         PTMP_FILE, strerror(errno));
  259.     }
  260.     return;
  261. }
  262.  
  263.  
  264. /*
  265.  *----------------------------------------------------------------------
  266.  *
  267.  *  removeFromMailingLists --
  268.  * 
  269.  *      Remove a user from all the mailing list.
  270.  *
  271.  * Results:
  272.  *    None.
  273.  *
  274.  * Side effects:
  275.  *      Modifies /sprite/lib/sendmail/aliases.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279. static void
  280. removeFromMailingLists(username)
  281.     CONST char *username;
  282. {
  283.     int status;            /* exit status from subprocesses */
  284.     char message[4096];        /* log message for "ci" and user prompt */
  285.     
  286.     /* 
  287.      * For the time being, rather than try to get string manipulation 
  288.      * code right, just invoke an editor and let the user remove all 
  289.      * instances of the name.
  290.      */
  291.     sprintf(message, "Remove %s from the aliases file?", username);
  292.     if (!yes(message)) {
  293.     return;
  294.     }
  295.  
  296.     sprintf(message, "-mdeleteuser: remove %s.", username);
  297.     
  298.     status = rcsCheckOut(ALIASES);
  299.     if (status < 0) {
  300.     exit(EXIT_FAILURE);
  301.     } else if (status != 0) {
  302.     goto error;
  303.     }
  304.  
  305.     /* 
  306.      * Give the user ownership of the file, so that she can edit it.
  307.      */
  308.     if (chown(ALIASES, getuid(), -1)  != 0) {
  309.     perror("Can't chown the aliases file");
  310.     goto error;
  311.     }
  312.  
  313.     if (Misc_InvokeEditor(ALIASES) != 0) {
  314.     fprintf(stderr, "Couldn't invoke editor.\n");
  315.     goto error;
  316.     }
  317.  
  318.     /* 
  319.      * Check the aliases file back in, even if we didn't actually make 
  320.      * any changes.
  321.      */
  322.     status = rcsCheckIn(ALIASES, message);
  323.     if (status == 0) {
  324.     printf("Removed %s from aliases file.\n", username);
  325.     } else {
  326.     fprintf(stderr, "\nPlease check the aliases file.\n");
  327.     fprintf(stderr, "(Make sure that `%s' is no longer in any lists\n",
  328.            username);
  329.     fprintf(stderr, "and that the file was checked in.)\n\n");
  330.     }
  331.     return;
  332.  
  333.  error:
  334.     fprintf(stderr,
  335.         "\nWarning: unable to remove `%s' from the aliases file.\n",
  336.         username);
  337.     fprintf(stderr, "You'll have to edit the aliases file by hand.\n\n");
  338.     return;
  339. }
  340.  
  341.  
  342. /*
  343.  *----------------------------------------------------------------------
  344.  *
  345.  * removeHomeDirectory --
  346.  *
  347.  *    Remove a home directory.
  348.  *
  349.  * Results:
  350.  *    None.
  351.  *
  352.  * Side effects:
  353.  *    Deletes all the files in the directory and then unlinks it.  
  354.  *    If the given directory is really a symbolic link, removes the 
  355.  *    link and the directory it points to.
  356.  *
  357.  *----------------------------------------------------------------------
  358.  */
  359. static void
  360. removeHomeDirectory(givenDir)
  361.     CONST char *givenDir;    /* path to the directory, usually a 
  362.                  * link to the real home directory */
  363. {
  364.     char actualDir[MAXPATHLEN]; /* the real home directory */
  365.     char command[MAXPATHLEN + 20]; /* passed to system() */
  366.     struct stat statBuf;
  367.     int n;
  368.  
  369.     if (lstat(givenDir, &statBuf) < 0) {
  370.     fprintf(stderr, "Can't stat %s: %s\n", givenDir,
  371.         strerror(errno));
  372.     return;
  373.     }
  374.     if ((statBuf.st_mode & S_IFMT) == S_IFDIR) {
  375.     strcpy(actualDir, givenDir);
  376.     } else if ((statBuf.st_mode & S_IFMT) == S_IFLNK) {
  377.     n = readlink(givenDir, actualDir, sizeof(actualDir));
  378.     if (n < 0) {
  379.         fprintf(stderr, "Cannot read link %s: %s.\n",
  380.             givenDir, strerror(errno));
  381.         return;
  382.     }
  383.     actualDir[n] = '\0';
  384.     } else {
  385.     fprintf(stderr,
  386.         "%s isn't a link or a directory; not removing.\n", 
  387.         givenDir);
  388.     return;
  389.     }
  390.  
  391.     /* 
  392.      * actualDir now contains the path for the directory we want to 
  393.      * delete.
  394.      */
  395.  
  396.     if ((statBuf.st_mode & S_IFMT) == S_IFLNK) {
  397.     printf("removing symbolic link: %s\n", givenDir);
  398.     if (unlink(givenDir)) {
  399.         (void) fprintf(stderr, "Cannot unlink %s: %s\n",
  400.                givenDir, strerror(errno));
  401.     }
  402.     }
  403.     printf("removing home directory: %s\n", actualDir);
  404.     (void) sprintf(command, "rm -rf %s", actualDir);
  405.     if (system(command) != 0) {
  406.     (void) fprintf(stderr, "Error deleting files from %s.\n", actualDir);
  407.     }
  408.     return;
  409. }
  410.